﻿#define _CRT_SECURE_NO_WARNINGS
#include <vector>
#include<assert.h>
#include <algorithm>
#include"string.h"
using namespace std;
//测试用的字符串类
namespace Boogle1
{
	class Solution {
	public:
		// 传值返回需要拷贝
		string addStrings(string num1, string num2) {
			string str;
			int end1 = num1.size() - 1, end2 = num2.size() - 1;
			// 进位
			int next = 0;
			while (end1 >= 0 || end2 >= 0)
			{
				int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
				int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
				int ret = val1 + val2 + next;
				next = ret / 10;
				ret = ret % 10;
				str += ('0' + ret);
			} 
			if(next == 1)
				str += '1';
			reverse(str.begin(), str.end());
			return str;
		}
	};
}
namespace Boogle2
{
	class Solution {
	public:
		// 这里的传值返回拷贝代价太大了
		vector<vector<int>> generate(int numRows) {
			vector<vector<int>> vv(numRows);
			for (int i = 0; i < numRows; ++i)
			{
				vv[i].resize(i + 1, 1);
			}
			for (int i = 2; i < numRows; ++i)
			{
				for (int j = 1; j < i; ++j)
				{
					vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
				}
			}
			return vv;
		}
	};
}

//左值右值和左值引用右值引用
void test1()
{
	//左值特点是可以取地址
	int a = 10; //左值，可以取地址，可以赋值
	int b = 20; //左值，可以取地址，可以赋值
	int* p = new int(10); //左值，可以取地址，可以赋值
	string s = ("hello"); //左值，可以取地址，可以赋值
	//s[0] = "x";
	//右值特点是不能取地址，不能赋值
	a + b;
	10;
	fmin(a, b);
	string("world");
	//左值引用
	int& r1 = b;
	int*& r2 = p;
	int& r3 = *p;
	string& r4 = s;
	char& r5 = s[0];
	//右值引用
	int&& rr1 = 10;
	double&& rr2 = a + b;
	double&& rr3 = fmin(a, b);
	string&& rr4 = string("11111");
	// 左值引用不能直接引用右值，但是const左值引用可以引用右值
	const int& rx1 = 10;
	const double& rx2 = a + b;
	const double& rx3 = fmin(a, b);
	const string& rx4 = string("11111");
	// 右值引用不能直接引用左值，但是右值引用可以引用move(左值)
	int&& rrx1 = move(b);
	int*&& rrx2 = move(p);
	int&& rrx3 = move(*p);
	string&& rrx4 = move(s);
	string&& rrx5 = (string&&)s;
	// b、r1、rr1都是变量表达式，都是左值
	cout << &b << endl;
	cout << &r1 << endl;
	cout << &rr1 << endl;
	// 这里要注意的是，rr1的属性是左值，所以不能再被右值引用绑定，除非move一下
	int& r6 = r1;
	// int&& rrx6 = rr1;
	int&& rrx6 = move(rr1);
}
//延长声明周期
void test2()
{
	//std::string s1 = "test";
	//std::string&& r1 = s1; // 错误：不能绑定到左值
	//const std::string& r2 = s1 + s1; // ok：到 const 的左值引用延长生存期
	//r2 += "test"; // 错误：不能通过到 const 的引用修改
	//std::string&& r3 = s1 + s1; // ok：右值引用延长生存期
	//r3 += "test"; // ok：能通过到非 const 的引用修改
	//std::cout << r3 << '\n';
}
//左右值引用重载
void f(int& x)
{
	std::cout << "左值引用重载 f(" << x << ")\n";
} 
void f(const int& x)
{
	std::cout << "到 const 的左值引用重载 f(" << x << ")\n";
} 
void f(int&& x)
{
	std::cout << "右值引用重载 f(" << x << ")\n";
}
void test3()
{
	int i = 1;
	const int ci = 2;
	f(i); // 调用 f(int&)
	f(ci); // 调用 f(const int&)
	f(3); // 调用 f(int&&)，如果没有 f(int&&) 重载则会调用 f(const int&)
	f(std::move(i)); // 调用f(int&&)
	// 右值引用变量在用于表达式时是左值
	int&& x = 1;
	f(x); // 调用 f(int& x)
	f(std::move(x)); // 调用 f(int&& x)
}
// 自定义字符串类测试
void test4()
{
	string_h::string s1("xxxxxxx");
	// 拷贝构造
	string_h::string s2 = s1;
	//右值拷贝，马上就要销毁了
	//调用移动构造函数
	string_h::string s3 = string_h::string("yyyyyyy");
	//不要轻易对左值move
	string_h::string s4 = move(s1);
	string_h::string ret = string_h::addStrings("11111", "2222");
	//cout << ret.c_str() << endl;
}
//移动语义
void test5()
{
	int i = 10;
	int &r=i;
	int &&r2 = 10;
	//无法将左值绑定到右值引用
	//int &&r3 = r2;
	//要move一下才可以
	int &&r4 = move(r2);
	//或者类型强转
	int&& r5 = (int&&)r2;
}
// 引⽤折叠
// 由于引⽤折叠限定，f1实例化以后总是⼀个左值引⽤
template<class T>
void f1(T& x)
{
}
// 由于引⽤折叠限定，f2实例化后可以是左值引⽤，也可以是右值引⽤
//因为这个特性，也叫做万能引用
template<class T>
void f2(T&& x)
{
}
void test6()
{
	typedef int& lref;
	typedef int&& rref;
	using lref = int&;//新标准也可以使用这个来重定义
	int n = 0;
	lref& r1 = n; // r1 的类型是 int&
	lref&& r2 = n; // r2 的类型是 int&
	rref& r3 = n; // r3 的类型是 int&
	rref&& r4 = 1; // r4 的类型是 int&&
	// 没有折叠->实例化为void f1(int& x)
	//f1<int>(n);
	//f1<int>(0); // 报错，实际上为左值引用重载
	//// 折叠->实例化为void f1(int& x)
	//f1<int&>(n);
	//f1<int&>(0); // 报错
	//// 折叠->实例化为void f1(int& x)
	//f1<int&&>(n);
	//f1<int&&>(0); // 报错
	//// 折叠->实例化为void f1(const int& x)
	//f1<const int&>(n);
	//f1<const int&>(0);
	//// 折叠->实例化为void f1(const int& x)
	//f1<const int&&>(n);
	//f1<const int&&>(0);
	//// 没有折叠->实例化为void f2(int&& x)
	//f2<int>(n); // 报错
	//f2<int>(0);
	//// 折叠->实例化为void f2(int& x)
	//f2<int&>(n);
	//f2<int&>(0); // 报错
	//// 折叠->实例化为void f2(int&& x)
	//f2<int&&>(n); // 报错
	//f2<int&&>(0);
}
//万能引用，既可以实例化出左值版本又可以实例化出右值版本
//template<class T>
//void Function(T&& t)
//{
//	int a = 0;
//	T x = a;
//	cout<<"&x=" << &x << endl;
//	cout<<"&a=" << &a << endl;
//}
//void test7()
//{
//	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(10); // 右值
//	int a;
//	// a是左值，推导出T为int&，引⽤折叠，模板实例化为void Function(int& t)
//	Function(a); // 左值
//	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)
//	Function(std::move(a)); // 右值
//	const int b = 8;
//	// a是左值，推导出T为const int&，引⽤折叠，模板实例化为void Function(const int&t)
//	// 所以Function内部会编译报错，x不能++
//	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
//	// 所以Function内部会编译报错，x不能++
//	Function(std::move(b)); // const 右值
//	Function(b);
//}
//万能转发
template <class _Ty>
_Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept
{ // forward an lvalue as either an lvalue or an rvalue
	return static_cast<_Ty&&>(_Arg);
} 
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
template<class T>
void Function(T&& t)
{
	Fun(t);
	//Fun(forward<T>(t));
}
void test8()
{
	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)
	Function(10); // 右值
	int a;
	// a是左值，推导出T为int&，引⽤折叠，模板实例化为void Function(int& t)
	Function(a); // 左值
	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)
	Function(std::move(a)); // 右值
	const int b = 8;
	// a是左值，推导出T为const int&，引⽤折叠，模板实例化为void Function(const int&t)
	Function(b); // const 左值
	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
	Function(std::move(b)); // const 右值
}
int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	//function(10);
	//test6();
	//test7();
	test8();
	return 0;
}
